﻿using System;
using System.Collections.Generic;
using Cysharp.Threading.Tasks;
using FrameWork.UICore;
using FrameWork.Util;
using FrameWork.Util.Expansion;
using Settings;
using UnityEngine;
using UnityEngine.UI;
using Object = UnityEngine.Object;
using Transform = UnityEngine.Transform;

namespace FrameWork.Managers
{
    public partial class UIManager : BaseManager
    {
        internal UIManager(ConstructorToken constructorToken = null) : base(constructorToken)
        {
            
        }

        public static UIManager GetInstance()
        {
            return GameManager.Instance.UIManager;
        }

        private readonly Dictionary<EUILayer, UIContainer> _dicUIContainer = new Dictionary<EUILayer, UIContainer>();
        private readonly Dictionary<Type, UIMetaAttribute>  _dicUIMetaCache = new Dictionary<Type, UIMetaAttribute>();
        
        private readonly Dictionary<EUILayer, Transform> _dicUILayerRoot = new Dictionary<EUILayer, Transform>();

        public Transform UIRoot { get; private set; }


        public override UniTask OnInitStart()
        {
            InitUIRoot();
            
            _dicUIContainer.Clear();
            
            _dicUIContainer.Add(EUILayer.None, new UIContainer(EUILayer.None));
            _dicUIContainer.Add(EUILayer.MainUI, new UIContainer(EUILayer.MainUI));
            _dicUIContainer.Add(EUILayer.CommonUI, new UIContainer(EUILayer.CommonUI));
            _dicUIContainer.Add(EUILayer.CommonPop, new UIContainer(EUILayer.CommonPop));
            _dicUIContainer.Add(EUILayer.TipPop, new UIContainer(EUILayer.TipPop));
            _dicUIContainer.Add(EUILayer.Tips, new UIContainer(EUILayer.Tips));
            _dicUIContainer.Add(EUILayer.SystemTip, new UIContainer(EUILayer.SystemTip));
            return UniTask.CompletedTask;
        }

        private void InitUIRoot()
        {
            UIRoot = new GameObject("UIRoot").transform;
            Object.DontDestroyOnLoad(UIRoot);
            UIRoot.ResetLocal();
            
            foreach (EUILayer layer in Enum.GetValues(typeof(EUILayer)))
            {
                string name = layer.ToString(); 
                var uiLayerRoot = new GameObject($"UILayerRoot_{name}");
                
                var canvas = uiLayerRoot.AddComponent<Canvas>();
                canvas.renderMode = RenderMode.ScreenSpaceOverlay;
                canvas.sortingOrder = (int)layer * 100;
                canvas.pixelPerfect = true;
                canvas.vertexColorAlwaysGammaSpace = true;
                
                var canvasScaler = uiLayerRoot.AddComponent<CanvasScaler>();
                canvasScaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
                canvasScaler.screenMatchMode = CanvasScaler.ScreenMatchMode.MatchWidthOrHeight;
                canvasScaler.referenceResolution = new Vector2(1920, 1080);
                canvasScaler.matchWidthOrHeight = 0.0f;
                
                uiLayerRoot.transform.SetParentAndResetLocal(UIRoot);
                
                var root = new GameObject("Root");
                root.transform.SetParentAndResetLocal(uiLayerRoot.transform);
                var rect = root.AddComponent<RectTransform>();
                rect.anchorMin = new Vector2(0, 0);  
                rect.anchorMax = new Vector2(1, 1);  
                rect.offsetMin = Vector2.zero; 
                rect.offsetMax = Vector2.zero;
                rect.pivot = new Vector2(0.5f, 0.5f);
                
                //存rect 方便以后做屏幕适配
                _dicUILayerRoot.Add(layer, rect.transform);
                
                var container = new UIContainer(layer);
                _dicUIContainer.Add(layer, container);
            }
        }

        public UIMetaAttribute GetUIMeta<T>() where T : UIBase
        {
            var type = typeof(T);
            if (_dicUIMetaCache.TryGetValue(type, out var meta))
                return meta;
            
            var attributeType = typeof(UIMetaAttribute);
        
            // 直接访问特性实例
            var attribute = (UIMetaAttribute)Attribute.GetCustomAttribute(
                typeof(T), 
                attributeType
            );

            if (attribute == null)
            {
                if(GameDefine.EnableLog)
                    FLogger.LogError($">>> error : 获取UI Meta失败， { type.Name } : 未声明 <UIPath> 特性！");
                return null;
            }
            else
            {
                _dicUIMetaCache.TryAdd(type, attribute);
            }
            
            return attribute;
        }

        public string GetUIPath<T>() where T : UIBase
        {
            var attribute = GetUIMeta<T>();
            if (attribute == null)
            {
                if(GameDefine.EnableLog)
                    FLogger.LogError($">>> error : 获取UI Meta失败， { typeof(T).Name } : 未声明 <UIPath> 特性！");
                return null;
            }

            return attribute.Path;
        }
        
        public async UniTask<T> OpenUI<T>() where T : UIBase
        {
            var attribute = GetUIMeta<T>();
            if (attribute == null)
            {
                return null;
            }

            string path = attribute.Path;
            if (string.IsNullOrEmpty(path))
            {
                return null;
            }
            
            var obj = await ResourcesManager.GetInstance().LoadPrefab(path);

            if (!obj)
            {
                if (GameDefine.EnableLog)
                    FLogger.LogError($">>> error : 加载ui预制体失败 path : {path} ");
                return null;
            }

            var ui = obj.GetComponent<T>();
            if (!ui)
            {
                if (GameDefine.EnableLog)
                    FLogger.LogError($">>> error : 获取ui组件失败 typeof(T) : {typeof(T).FullName} ");
                obj.SetActive(false);
                Object.Destroy(obj);
                return null;
            }
            
            var layer = attribute.UILayer;
            var container = GetContainer(layer);

            container.OnOpenUI(ui);
            
            return ui;
        }
        
        private UIContainer GetContainer(EUILayer layer)
        {
            return _dicUIContainer.GetValueOrDefault(layer);
        }

        public bool IsOpen<T>() where T : UIBase
        {
            var attribute = GetUIMeta<T>();
            if (attribute == null)
                return false;
            
            var layer = attribute.UILayer;
            
            var container = GetContainer(layer);
            return container != null && container.HasUI<T>();
        }

        public Transform GetUILayerRoot(EUILayer layer)
        {
            return _dicUILayerRoot[layer];
        }
    }
    
    
}